import path from 'path'
import fs from 'fs'
import { DataType, Definitions, SchemaType, UsePaths } from '../../interface/swagger'
import {
  TranslationNormalType,
  TranslationPropType,
  getRequestNameByPath,
  hasKey,
  isNormalType,
  removeBreakNblank,
  removeComponenStr,
  removeDefine
} from '../../utils'
export const handleSchema = (schema: SchemaType) => {
  if (hasKey(schema, '$ref')) {
    // 直接指向vo
    return removeDefine(schema.$ref!)
  } else if (hasKey(schema, 'type')) {
    if (schema.type === DataType.Array && hasKey(schema, 'items')) {
      const baseValue = handleItems(schema.items!)
      return `${baseValue}[]`
    } else {
      // 普通类型，需要搭配name使用
      return schema.type
    }
  }
}
export const handleItems = (items: SchemaType) => {
  if (hasKey(items, '$ref')) {
    // 直接指向vo
    let item = removeComponenStr(items.$ref!)
    item = removeDefine(item)
    return item
  } else if (hasKey(items, 'type')) {
    if (items.type === DataType.Array && hasKey(items, 'items')) {
      const baseValue: any = handleItems(items.items!)
      return `${baseValue}[]`
    } else {
      // 普通类型，需要搭配name使用
      return TranslationNormalType(items.type!)
    }
  }
}

/**
 * 生成api函数
 */
export const getTsApiLine = (useFileName: string, item: UsePaths) => {
  const summary = item.summary
  const perfix = summary
    ? `/** ${summary} */\nexport function ${getRequestNameByPath(item.url)}`
    : `export function ${getRequestNameByPath(item.url)}`
  const req =
    getReq(useFileName, item.params) !== 'null'
      ? `(params: ${removeBreakNblank(getReq(useFileName, item.params))}) {\n`
      : '(){\n'
  const requestFun = `\treturn request.${item.method}<${removeBreakNblank(
    getRes(useFileName, item.response)!
  )}>`
  const sufix =
    getReq(useFileName, item.params) !== 'null'
      ? `('${item.url}',params)\n}\n\n`
      : `('${item.url}', {})\n}\n\n`
  return perfix + req + requestFun + sufix
}

/**
 * 获取请求参数的名字
 */
export const getReq = (useFileName: string, params?: string) => {
  if (!params) {
    return 'null'
  }
  if (params.includes('{')) {
    // 自定义对象
    return params
  } else {
    return `${apiName(useFileName)}.${apiName(useFileName)}.${useFileName}.${params}`
  }
}

/**获取返回参数类型 */
export const getRes = (useFileName: string, response: string | undefined) => {
  if (!response) {
    // 没有指定参数返回
    return 'any'
  } else if (isNormalType(response)) {
    return response
  } else {
    return `${apiName(useFileName)}.${apiName(useFileName)}.${useFileName}.${response}`
  }
}

export const apiName = (str: string) => `${str.slice(0, 4)}Api`

/**获取js行 */
export const getJsApiLine = (useFileName: string, item: UsePaths) => {
  const summary = item.summary
  const params = item.params
  return `
   /** 
    * ${summary ? summary : ''} 
    * @param \{${item.params ? removeBreakNblank(getReq(useFileName, item.params)) : ''} } params
    * @returns \ {${item.response ? removeBreakNblank(getRes(useFileName, item.response)!) : ''} }
    * 
    * */
    export\ function\ ${getRequestNameByPath(item.url)}(${item.params ? 'params' : ''}) {
      return request.${item.method}(${item.url},${item.params ? 'params' : ''})
    }\n\n
    `
}

/**
 *
 * @param definitions vo值
 * @param defineName vo名
 * @param work 工作模式
 * @returns 返回字符串：
 *  interface defineName {
 *    agv1: string | number | bool
 *    agv2: srting[] | number[] | bool[]
 *    agv3: vo值[] // 此时会再生成一个vo值，如果依然嵌套，继续生成
 *  }
 */
// 全局记录VO数组嵌套数组
export const supplementArr: { arr1: string[]; arr2: string[] } = {
  arr1: [],
  arr2: []
}
export function getProperties(
  definitions: Definitions,
  defineName: string,
  work: WorkeMod = WorkeMod.Normal
) {
  defineName = removeDefine(defineName)
  defineName = removeComponenStr(defineName)
  const propItem = definitions[`${defineName}`].properties
  let line = `interface ${defineName}{\n`
  // 如果是$ref嵌套，补充需要的VO类
  let standby = ''
  Object.keys(propItem).forEach((voKey) => {
    const description = propItem[voKey].description
    if (hasKey(propItem[voKey], '$ref')) {
      // 有$ref， 出现嵌套现象
      let _voKey = removeDefine(propItem[voKey].$ref!)
      _voKey = removeComponenStr(propItem[voKey].$ref!)
      _voKey = removeDefine(_voKey)
      _voKey = removeComponenStr(_voKey)
      const $ref = getProperties(definitions, _voKey)
      standby += '\n' + $ref
      line += `\t${voKey}: ${_voKey} \n`
    } else if (hasKey(propItem[voKey], 'type')) {
      if (propItem[voKey].type === DataType.Array) {
        // 数组类型继续找items
        const arrayName = handleItems(propItem[voKey].items!)
        if (!isNormalType(arrayName!)) {
          // 指向另外一个vo
          work === WorkeMod.Arr
            ? supplementArr.arr2.push(arrayName!)
            : supplementArr.arr1.push(arrayName!)
        }
        line += description
          ? ` /** ${description} */\n ${voKey} : ${arrayName}[];\n`
          : ` \t${voKey} : ${arrayName}[];\n`
      } else {
        // 普通类型的值
        line += description
          ? `/** ${description} */\n ${voKey}: ${TranslationPropType(propItem[voKey].type)};\n`
          : `\t${voKey}: ${TranslationPropType(propItem[voKey].type)};\n`
      }
    }
  })
  return line + '\n}' + standby + '\n\t'
}
/**
 * 处理嵌套层里的VO
 */
export function handleNestVo(definitions: Definitions) {
  let defineLine = ''
  // 补充数组指向缺少的字段
  supplementArr.arr1.forEach((defineName, index) => {
    // 传入数组模式
    const _define = getProperties(definitions, defineName, WorkeMod.Arr)
    defineLine += _define + '\n'
  })
  supplementArr.arr2.forEach((defineName) => {
    // 数组嵌套数组模式
    const _define = getProperties(definitions, defineName, WorkeMod.Arr)
    defineLine += _define + '\n'
  })
  supplementArr.arr1.length = 0
  supplementArr.arr2.length = 0
  return defineLine
}
// 工作模式
export enum WorkeMod {
  Normal = 1,
  Arr = 2
}

export function writeFile(
  dirPath: string,
  fileName: string,
  fileLine: string,
  defineLine: string,
  isJs: boolean = false
) {
  const fileType = isJs ? '.js' : '.ts'
  const defineFilePath = path.join(__dirname, dirPath, fileName + '.d.ts')
  const filePath = path.join(__dirname, dirPath, fileName + fileType)
  const writeDefine = fs.promises.writeFile(defineFilePath, defineLine)
  const writeTs = fs.promises.writeFile(filePath, fileLine)
  return {
    writeDefine,
    writeTs
  }
}
